@file:Suppress("SpellCheckingInspection", "unused")

package com.example.base.aop.permission

import android.os.Build
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.example.base.BaseApp
import com.example.base.R
import com.example.base.ext.toast
import com.therouter.getApplicationContext
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Pointcut
import org.aspectj.lang.reflect.MethodSignature
import java.lang.reflect.Method

/**  动态权限申请切面处理类  **/
@Aspect
class PermissionAspect {

    companion object {
        /**  方法切入规则  **/
        private const val POINTCUT_METHOD =
            "execution(@com.example.base.aop.permission.PermissionRequest * *(..))"
    }

    @Pointcut(POINTCUT_METHOD)
    fun methodAnnotatedWithPermission() {
    }

    @Throws(Throwable::class)
    @Around("methodAnnotatedWithPermission()")
    fun aroundJoinPoint(joinPoint: ProceedingJoinPoint) {
        // check environment
        val annotatedTarget = joinPoint.target
        val currentActivity = BaseApp.ActivityManager.getCurrentActivity()
        val activity: FragmentActivity
        if (currentActivity != null) {
            activity = currentActivity as FragmentActivity
        } else {
            activity = when (annotatedTarget) {
                is FragmentActivity -> annotatedTarget
                is Fragment -> annotatedTarget.requireActivity()
                else -> throw PermissionRequestException("The PermissionRequest annotation can only be used in FragmentActivity or Fragment environment!")
            }
        }


        // get infomations
        val methodSignature = joinPoint.signature as MethodSignature
        val method = methodSignature.method
        val annotation = method.getAnnotation(PermissionRequest::class.java)!!
        val requestPermissions = annotation.value
        val limitVERSION = annotation.limitVERSION

        if (Build.VERSION.SDK_INT >= limitVERSION || limitVERSION <= 0) {
            // request permission
            PermissionTool.getInstance(activity)
                .request(requestPermissions)
                .execute(
                    CustomRequestPermissionCallback(
                        activity, joinPoint,
                        annotatedTarget, requestPermissions
                    )
                )
        } else {
            // 若不存在自定义失败回调, 则进入默认处理
            joinPoint.proceed()

        }


    }

    /**  获取权限申请失败时的回调方法, 若不存在该方法, 则返回 null  **/
    private fun getPermissionRequestErrorCallback(annotatedTarget: Any): Method? {
        for (method in annotatedTarget.javaClass.methods) {
            if (method.isAnnotationPresent(PermissionRequestError::class.java)) {
                method.isAccessible = true
                return method
            }
        }
        return null
    }

    /**  自定义内部动态权限申请回调接口实现类  **/
    private inner class CustomRequestPermissionCallback(
        private val activity: FragmentActivity,
        private val joinPoint: ProceedingJoinPoint,
        private val annotatedTarget: Any,
        private val requestPermissions: Array<out String>,
    ) : RequestPermissionCallback {
        override fun onSuccess() {
            joinPoint.proceed()
        }

        override fun onError(notGrantedPermissions: Array<out String>) {
            // 若不存在自定义失败回调, 则进入默认处理
            val permissionRequestErrorCallback =
                getPermissionRequestErrorCallback(annotatedTarget)
            if (null == permissionRequestErrorCallback) {
                activity.toast(activity.getString(R.string.request_permission_deny_hint))
                return
            }

            // 调用自定义回调
            callRequestErrorCallback(permissionRequestErrorCallback)
        }

        /**  调用开发者自定义错误回调  **/
        private fun callRequestErrorCallback(permissionRequestErrorCallback: Method) {
            // 存在自定义失败回调, 则获取回调的参数列表, 若符合规则则进行调用, 若不符合规则则抛出异常
            val paramsTypes = permissionRequestErrorCallback.parameterTypes
            when {
                // 存在自定义回调, 并且接收参数为 String 数组, 则直接调用并传入请求的权限集合
                (paramsTypes.size == 1) and paramsTypes[0].isArray and (paramsTypes[0].componentType == String::class.java) ->
                    permissionRequestErrorCallback.invoke(
                        annotatedTarget,
                        requestPermissions
                    )
                // 存在自定义回调, 但无接收参数, 则直接进行回调调用
                paramsTypes.isEmpty() -> permissionRequestErrorCallback.invoke(annotatedTarget)
                // 其他情况则为使用规则有误, 直接抛出异常
                else -> throw PermissionRequestException("The PermissionRequestError annotation can only be used in method params type of empty or String array!")
            }
        }
    }
}